home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / appletalk / uab.shar / ddprouter.c < prev    next >
C/C++ Source or Header  |  1990-07-12  |  13KB  |  458 lines

  1. static char rcsid[] = "$Author: cck $ $Date: 88/09/14 10:19:10 $";
  2. static char rcsident[] = "$Header: /src/local/mac/cap/etalk/RCS/ddprouter.c,v 1.18 88/09/14 10:19:10 cck Rel $";
  3. static char revision[] = "$Revision: 1.18 $";
  4.  
  5. /*
  6.  * ddprouter.c - simple ddp router
  7.  *
  8.  * Follows specification set in "Inside Appletalk" by Gursharan Sidhu,
  9.  * Richard F. Andrews, and Alan B. Oppenheimer, Apple Computer, Inc.
  10.  * June 1986.
  11.  *
  12.  * Copyright (c) 1988 by The Trustees of Columbia University 
  13.  *  in the City of New York.
  14.  *
  15.  * Permission is granted to any individual or institution to use,
  16.  * copy, or redistribute this software so long as it is not sold for
  17.  * profit, provided that this notice and the original copyright
  18.  * notices are retained.  Columbia University nor the author make no
  19.  * representations about the suitability of this software for any
  20.  * purpose.  It is provided "as is" without express or implied
  21.  * warranty.
  22.  *
  23.  *
  24.  * Edit History:
  25.  *
  26.  *  August, 1988  CCKim Created
  27.  *
  28. */
  29.  
  30. static char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
  31. Columbia University in the City of New York";
  32.  
  33. #include <stdio.h>
  34. #include <ctype.h>
  35. #include <sys/types.h>
  36. #include <sys/socket.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/uio.h>
  39. #include <sys/time.h>
  40. #include <net/if.h>
  41. #include <netinet/in.h>
  42.  
  43. #include <netat/appletalk.h>
  44. #include "gw.h"
  45.  
  46. export void ddp_route_init();
  47. export void ddp_route_start();
  48. export void sddp_route();
  49. export void ddp_route();
  50. export int ddp_open();        /* local ddp routines */
  51. export int ddp_reopen();
  52. private void ddp_input();
  53. export void ddp_output();
  54. private int ddp_matchournode();
  55. private void dump_types();
  56. export void ddp_dump_stats();
  57.  
  58. #define NUMDDPTYPES 8
  59. char *ddp_type_names[NUMDDPTYPES] = {
  60.   "unknown", "RTMP", "NBP", "ATP", "ECHO", "RTMP Request", "ZIP", "ADSP"
  61. };
  62.  
  63. #define valid_type(d) (((d)->type>=ddpRTMP&&(d)->type<=ddpADSP)?(d)->type:0)
  64.                
  65.  
  66. struct ddp_stats {
  67.   int short_ddp_routed;        /* short ddp sent to router */
  68.   int long_ddp_routed;        /* long ddp sent to router */
  69.   int ddp_forwarded;        /* long ddp forwarded */
  70.   int ddp_types_forwarded[NUMDDPTYPES];    /* breakdown by type */
  71.   int drop_noroute;        /* no routes */
  72.   int drop_hops;        /* dropped because of hops */
  73.   int long_ddp_output;        /* long ddp output */
  74.   int long_ddp_types_output[NUMDDPTYPES]; /* breakdown by type */
  75.   int short_ddp_output;        /* short ddp output */
  76.   int short_ddp_types_output[NUMDDPTYPES];
  77.   int ddp_input;        /* ddp packets input */
  78.   int ddp_types_input[NUMDDPTYPES];
  79. };
  80.  
  81. private struct ddp_stats ddp_stats;
  82.  
  83. /* note: open for all ports */
  84. private boolean (*ddp_handlers[ddpMaxSkt+1])(); /* define internal sockets */
  85.  
  86. /*
  87.  * start ddp routing - need address of an internal router though to allow
  88.  * mpx and aux. services (takes long ddp header, data and datalength )
  89.  *
  90.  * beabridge set to true tells us to tell rtmp to output rtmp packets
  91.  * and to answer rtmp request packets
  92.  *
  93. */
  94. export void
  95. ddp_route_start()
  96. {
  97.   rtmp_start();
  98.   ddp_svcs_start();        /* start if needed (says we know net) */
  99. }
  100.  
  101. /*
  102.  * give us a chance to initialize.
  103.  *
  104. */
  105. export void
  106. ddp_route_init()
  107. {
  108.   int i;
  109.  
  110.   for (i = 1 ; i < ddpMaxSkt; i++)
  111.     ddp_handlers[i] = NULL;
  112.   rtmp_init();
  113.   ddp_svcs_init();        /* init other ddp services */
  114. }
  115.  
  116. /*
  117.  * route a short ddp packet coming in from an interface
  118.  * 
  119.  * basically, make the short header into a long ddp header and deliver
  120.  * internally
  121.  *
  122.  * ddps is aligned okay, cannot assume for data
  123. */
  124. export void
  125. sddp_route(port, srcnode, ddps, data, datalen)
  126. PORT_T port;
  127. byte srcnode;
  128. ShortDDP *ddps;
  129. byte *data;
  130. int datalen;
  131. {
  132.   DDP ddp;
  133.   int i;
  134.  
  135.   /* get indicated data length */
  136.   i = (ddpLengthMask & ntohs(ddps->length)) - ddpSSize;
  137.   if (i < datalen)        /* reduce in case caller is enet, etc. */
  138.     datalen = i;
  139.   ddp.length = htons(datalen + (ddpSize-ddpSSize));
  140.   ddp.checksum = 0;
  141.   ddp.srcNet = ddp.dstNet = PORT_DDPNET(port);
  142.   ddp.srcNode = srcnode;
  143.   ddp.dstNode = PORT_DDPNODE(port);
  144.   ddp.srcSkt = ddps->srcSkt;
  145.   ddp.dstSkt = ddps->dstSkt;
  146.   ddp.type = ddps->type;
  147.   ddp_stats.short_ddp_routed++;
  148.   ddp_input(port, &ddp, data, datalen);
  149. }
  150.  
  151. /*
  152.  * route a long ddp packet.
  153.  *
  154.  *
  155.  * ddp is aligned okay, cannot assume for data
  156. */
  157. export void
  158. ddp_route(port, ddp, data, datalen, isbroadcast)
  159. PORT_T port;
  160. DDP *ddp;
  161. byte *data;
  162. int datalen;
  163. int isbroadcast;        /* if port okay, then came in as broadcast */
  164. {
  165.   struct route_entry *re;
  166.   NODE *dstnode;
  167.   int i;
  168.  
  169.   /* get indicated data length */
  170.   i = (ddpLengthMask & ntohs(ddp->length)) - ddpSize;
  171.   if (i < datalen)        /* reduce in case caller is enet, etc. */
  172.     datalen = i ;
  173.  
  174.   ddp_stats.long_ddp_routed++;
  175.   /* don't do certain things if the packet comes internally (flagged */
  176.   /* by the fact that the port is null) */
  177.   if (port) {
  178.     /* if from self, then drop */
  179.     if (ddp_matchournode(ddp->srcNet, ddp->srcNode, FALSE)) {
  180.       return;
  181.     }
  182.     /* forward packets for self to self */
  183.     /* don't forward broadcasts 'cept to self*/
  184.     if (ddp->dstNet == PORT_DDPNET(port) &&
  185.     (isbroadcast || (ddp->dstNode == PORT_DDPNODE(port)))) {
  186.       ddp_input(port, ddp, data, datalen);
  187.       return;
  188.     }
  189.   }
  190.  
  191.   /* get route to send the packet on */
  192.   /* drop if no route or bad port */
  193.   if ((re = route_find(ddp->dstNet)) == NULL) {
  194.     ddp_stats.drop_noroute++;
  195.     return;            /* drop the packet */
  196.   }
  197.   if (PORT_BAD(re->re_port) || !PORT_CONNECTED(re->re_port)) {
  198.     ddp_stats.drop_noroute++;
  199.     return;
  200.   }
  201.   if (re->re_dist == 0) {
  202.     if (ddp->dstNode == PORT_DDPNODE(re->re_port)) {
  203.       ddp_input(re->re_port, ddp, data, datalen);
  204.       return;
  205.     }
  206.     if (ddp->dstNode == DDP_BROADCAST_NODE) /* deliver ourselves a copy */
  207.       ddp_input(re->re_port, ddp, data, datalen);
  208.     if (re->re_ddp_net == 0)    /* drop if no net established yet */
  209.       return;
  210.     dstnode = PORT_MAKENODE(re->re_port, ddp->dstNet, ddp->dstNode);
  211.     ddp_stats.long_ddp_output++;
  212.     ddp_stats.long_ddp_types_output[valid_type(ddp)]++;
  213.   } else {
  214.     /* move over into msg and skip first two bits, but only keep 4 bits */
  215.     int hops = ntohs(ddp->length) >> (8+2) & 0xf;
  216.  
  217.     if (re->re_ddp_net == 0)    /* drop if no net established yet */
  218.       return;
  219. #define DDP_MAXHOPS 15
  220. #define ddpHopShift 10        /* 10 bits to the left for hops */
  221.     if (hops >= DDP_MAXHOPS) {
  222.       ddp_stats.drop_hops++;
  223.       return;            /* drop it */
  224.     }
  225.     ddp->length = htons((ntohs(ddp->length)&ddpLengthMask)|hops<<ddpHopShift);
  226.     dstnode = re->re_bridgeid_p;
  227.     ddp_stats.ddp_forwarded++;
  228.     ddp_stats.ddp_types_forwarded[valid_type(ddp)]++;
  229.   }
  230.   /* wait until here in case for ourselves (okay) */
  231.   if (re->re_ddp_net == 0) {    /* drop if no net established yet */
  232.     return;
  233.   }
  234.   /* send it out */
  235.   PORT_SEND(re->re_port, dstnode, lapDDP, ddp, ddpSize, data, datalen);
  236. }
  237.  
  238. /*
  239.  * Internal DDP input/output routines
  240.  *
  241. */
  242.  
  243. /*
  244.  * ddp open - open socket for processing - maybe allow socket
  245.  * to be open on a single port only, but not necessary for now
  246.  *
  247.  * Generally, should only be for a very small number of priviledged
  248.  * sockets
  249. */
  250. export int
  251. ddp_open(ddpskt, handler)
  252. int ddpskt;
  253. boolean (*handler)();
  254. {
  255.   register PORT_T port;
  256.  
  257.   if (ddpskt > 0 && ddpskt < ddpMaxSkt) {
  258.     /* need to open mpx socket - remember to callback in mpx open too */
  259.     /* how to do ? */
  260.     ddp_handlers[ddpskt] = handler;
  261.     for (port = PORT_LIST_START(); port ; port = PORT_NEXT(port))
  262.       PORT_GRAB(port, ddpskt);
  263.     return(TRUE);
  264.   }
  265.   return(FALSE);
  266. }
  267.  
  268. /* smash through open socket list and call grab to grab the socket if */
  269. /* necessary (generally for mpx) */
  270. export int
  271. ddp_reopen(grab, arg, carg)
  272. int (*grab)();
  273. int arg;
  274. caddr_t carg;
  275. {
  276.   int i;
  277.  
  278.   for (i = 1; i < ddpMaxSkt; i++)
  279.     if (ddp_handlers[i])
  280.       (*grab)(i, arg, carg);
  281. }
  282.  
  283. /* 
  284.  * ddp input.  Processes an packet destined for internal use.
  285.  *
  286. */
  287. private void
  288. ddp_input(port, ddp, data, datalen)
  289. PORT_T port;
  290. DDP *ddp;
  291. byte *data;
  292. int datalen;
  293. {
  294.   int ds;            /* destination socket */
  295.  
  296.   ddp_stats.ddp_input++;
  297.  
  298.   /* should we checksum? - probably */
  299.   if (ddp->dstSkt == 0 || ddp->dstSkt == ddpMaxSkt) {
  300.     /* count ddp droped bad type */
  301.     return;
  302.   }
  303.  
  304.   /* rejct any packet from us (already know from us) */
  305.   /* that is a broadcast and whose srcSkt == dstSkt */
  306.   if (ddp_matchournode(ddp->srcNet, ddp->srcNode, FALSE) &&
  307.       ddp->dstNode == DDP_BROADCAST_NODE &&
  308.       ddp->dstSkt == ddp->srcSkt) {
  309.     /* RECORD */
  310.     return;
  311.   }
  312.   ds = ddp->dstSkt;
  313.   if (ddp_handlers[ds]) {
  314.     /* they return TRUE if they handle, false if we should try to */
  315.     /* forward it to an internal node */
  316.     if ((*(ddp_handlers[ds]))(port, ddp, data, datalen)) {
  317.       ddp_stats.ddp_types_input[valid_type(ddp)]++;
  318.       return;
  319.     }
  320.   }
  321.  
  322.   /* send to process if naught else */
  323.   if (port)  {
  324.     ddp_stats.ddp_types_input[valid_type(ddp)]++;
  325.     PORT_DEMUX(port, ddp, data, datalen);
  326.   }
  327. }
  328.  
  329. /*
  330.  * ddp output sends out a packet
  331.  *
  332.  * Special processing:
  333.  *  ddp output will output long ddp only if the appropriate flag is
  334.  *    set and sufficient input is given.
  335.  *  ddp output will also send back a broadcast packet to the input
  336.  *    routines if the "lap" layer is not capable of receiving its own
  337.  *    broadcasts
  338.  *
  339.  * Expect these ddp fields
  340.  *   dstNet
  341.  *   dstNode
  342.  *   dstSkt
  343.  *   srcSkt
  344.  *   type
  345.  * Fills in srcNet, srcNode, length, checksum with appropriate values
  346.  *
  347.  *
  348. */
  349. export void
  350. ddp_output(dstnode, ddp, data, size)
  351. NODE *dstnode;
  352. DDP *ddp;
  353. byte *data;
  354. int size;
  355. {
  356.   ShortDDP ddps;
  357.   struct route_entry *re;
  358.   PORT_T port;
  359.   byte pddpnode;
  360.  
  361.   /* make sure we can route to destination */
  362.   if ((re = route_find(ddp->dstNet)) == NULL)
  363.     return;
  364.   port = re->re_port;
  365.   pddpnode = PORT_DDPNODE(re->re_port);
  366.   
  367.   /* short ddp?  */
  368.   /* yes, if dstNet is same as outgoing port */
  369.   /* unless port wants long ddp and node was given */
  370.   /* have "special" case for no node in case it is not possible to map */
  371.   /* from "NODE *" type to a ddp node */
  372.   if (ddp->dstNet == PORT_DDPNET(port) &&
  373.       (dstnode || !PORT_WANTS_LONG_DDP(port))) {
  374.     /* yes */
  375.     ddps.length = htons(ddpSSize + size);
  376.     ddps.dstSkt = ddp->dstSkt;
  377.     ddps.srcSkt = ddp->srcSkt;
  378.     ddps.type = ddp->type;
  379.     if (ddp->dstNode == DDP_BROADCAST_NODE && PORT_NEEDS_BROADCAST(port)) {
  380.       sddp_route(port, pddpnode, &ddps, data, size);
  381.     } else if (ddp->dstNode == pddpnode) {
  382.       sddp_route(port, pddpnode, &ddps, data, size);
  383.       return;
  384.     }
  385.     if (dstnode || (dstnode = PORT_MAKENODE(port, 0, ddp->dstNode))) {
  386.       ddp_stats.short_ddp_output++;
  387.       ddp_stats.short_ddp_types_output[valid_type(ddp)]++;
  388.       PORT_SEND(port, dstnode, lapShortDDP, &ddps, ddpSSize, data, size);
  389.     }
  390.     return;
  391.   }
  392.   /* definitely should put checksum here !!!! */
  393.   ddp->checksum = 0;        /* should we put the checksum in? probably */
  394.   ddp->length = htons(size+ddpSize); /* length */
  395.   ddp->srcNet = PORT_DDPNET(port);
  396.   ddp->srcNode = pddpnode;
  397.   ddp_route(NULL, ddp, (byte *)data, size, FALSE);
  398. }
  399.  
  400.  
  401. /*
  402.  * Given a ddp network and node number, ddp matchournode will return true
  403.  * if it corresponds to the ddp network/node number of any port.
  404.  *
  405. */
  406. private int
  407. ddp_matchournode(net, node, br)
  408. register word net;
  409. register byte node;
  410. int br;
  411. {
  412.   register PORT_T port;
  413.  
  414.   for (port = PORT_LIST_START() ; port ; port = PORT_NEXT(port))
  415.     if ((net == 0 || PORT_DDPNET(port) == net) &&
  416.     ((br && node == DDP_BROADCAST_NODE) || PORT_DDPNODE(port) == node))
  417.       return(TRUE);
  418.   return(FALSE);
  419. }
  420.  
  421.  
  422. private void
  423. dump_types(fd, table)
  424. FILE *fd;
  425. int table[];
  426. {
  427.   int i;
  428.  
  429.   fprintf(fd, "  by type\n");
  430.   for (i = 1; i < NUMDDPTYPES; i++)
  431.     fprintf(fd, "\t%d %s\n", table[i], ddp_type_names[i]);
  432.   /* output "unknown last */
  433.   fprintf(fd, "\t%d %s\n", table[0], ddp_type_names[0]);
  434. }
  435.  
  436. export void
  437. ddp_dump_stats(fd)
  438. FILE *fd;
  439. {
  440.   fprintf(fd, "\nddp route\n");
  441.   fprintf(fd, " short ddp received: %d\n", ddp_stats.short_ddp_routed);
  442.  
  443.   fprintf(fd, " long ddp received: %d\n", ddp_stats.long_ddp_routed);
  444.   fprintf(fd, " forwarded to another bridge: %d\n", ddp_stats.ddp_forwarded);
  445.   dump_types(fd, ddp_stats.ddp_types_forwarded);
  446.   fprintf(fd, " output: %d\n", ddp_stats.long_ddp_output);
  447.   dump_types(fd, ddp_stats.long_ddp_types_output);
  448.  
  449.   fprintf(fd, " ddp packets input for node: %d\n", ddp_stats.ddp_input);
  450.   dump_types(fd, ddp_stats.ddp_types_input);
  451.  
  452.   fprintf(fd, " short ddp output: %d\n", ddp_stats.short_ddp_output);
  453.   dump_types(fd, ddp_stats.short_ddp_types_output);
  454.   fprintf(fd, " dropped: no route %d\n", ddp_stats.drop_noroute);
  455.   fprintf(fd, "\t   too many hops %d\n", ddp_stats.drop_hops);
  456. }
  457.  
  458.